#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"


static wxjpeg_boolean output_pass_setup JPP( ( j_decompress_ptr cinfo ) );

wxjpeg_boolean jpeg_start_decompress( j_decompress_ptr cinfo ) {
  if( cinfo->global_state == DSTATE_READY ) {
    /* First call: initialize master control, select active modules */
    jinit_master_decompress( cinfo );
    if( cinfo->buffered_image ) {
      /* No more work here; expecting jpeg_start_output next */
      cinfo->global_state = DSTATE_BUFIMAGE;
      return TRUE;
    }
    cinfo->global_state = DSTATE_PRELOAD;
  }
  if( cinfo->global_state == DSTATE_PRELOAD ) {
    /* If file has multiple scans, absorb them all into the coef buffer */
    if( cinfo->inputctl->has_multiple_scans ) {
      #ifdef D_MULTISCAN_FILES_SUPPORTED
      for( ;; ) {
        int retcode;
        /* Call progress monitor hook if present */
        if( cinfo->progress != NULL )
        { ( *cinfo->progress->progress_monitor )( ( j_common_ptr ) cinfo ); }
        /* Absorb some more input */
        retcode = ( *cinfo->inputctl->consume_input )( cinfo );
        if( retcode == JPEG_SUSPENDED )
        { return FALSE; }
        if( retcode == JPEG_REACHED_EOI )
        { break; }
        /* Advance progress counter if appropriate */
        if( cinfo->progress != NULL &&
            ( retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS ) ) {
          if( ++cinfo->progress->pass_counter >= cinfo->progress->pass_limit ) {
            /* jdmaster underestimated number of scans; ratchet up one scan */
            cinfo->progress->pass_limit += ( long ) cinfo->total_iMCU_rows;
          }
        }
      }
      #else
      ERREXIT( cinfo, JERR_NOT_COMPILED );
      #endif /* D_MULTISCAN_FILES_SUPPORTED */
    }
    cinfo->output_scan_number = cinfo->input_scan_number;
  } else if( cinfo->global_state != DSTATE_PRESCAN )
  { ERREXIT1( cinfo, JERR_BAD_STATE, cinfo->global_state ); }
  /* Perform any dummy output passes, and set up for the final pass */
  return output_pass_setup( cinfo );
}

static wxjpeg_boolean output_pass_setup( j_decompress_ptr cinfo ) {
  if( cinfo->global_state != DSTATE_PRESCAN ) {
    /* First call: do pass setup */
    ( *cinfo->master->prepare_for_output_pass )( cinfo );
    cinfo->output_scanline = 0;
    cinfo->global_state = DSTATE_PRESCAN;
  }
  /* Loop over any required dummy passes */
  while( cinfo->master->is_dummy_pass ) {
    #ifdef QUANT_2PASS_SUPPORTED
    /* Crank through the dummy pass */
    while( cinfo->output_scanline < cinfo->output_height ) {
      JDIMENSION last_scanline;
      /* Call progress monitor hook if present */
      if( cinfo->progress != NULL ) {
        cinfo->progress->pass_counter = ( long ) cinfo->output_scanline;
        cinfo->progress->pass_limit = ( long ) cinfo->output_height;
        ( *cinfo->progress->progress_monitor )( ( j_common_ptr ) cinfo );
      }
      /* Process some data */
      last_scanline = cinfo->output_scanline;
      ( *cinfo->main->process_data )( cinfo, ( JSAMPARRAY ) NULL,
                                      &cinfo->output_scanline, ( JDIMENSION ) 0 );
      if( cinfo->output_scanline == last_scanline )
      { return FALSE; }		/* No progress made, must suspend */
    }
    /* Finish up dummy pass, and set up for another one */
    ( *cinfo->master->finish_output_pass )( cinfo );
    ( *cinfo->master->prepare_for_output_pass )( cinfo );
    cinfo->output_scanline = 0;
    #else
    ERREXIT( cinfo, JERR_NOT_COMPILED );
    #endif /* QUANT_2PASS_SUPPORTED */
  }
  cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING;
  return TRUE;
}

JDIMENSION jpeg_read_scanlines( j_decompress_ptr cinfo, JSAMPARRAY scanlines,
                                JDIMENSION max_lines ) {
  JDIMENSION row_ctr;
  if( cinfo->global_state != DSTATE_SCANNING )
  { ERREXIT1( cinfo, JERR_BAD_STATE, cinfo->global_state ); }
  if( cinfo->output_scanline >= cinfo->output_height ) {
    WARNMS( cinfo, JWRN_TOO_MUCH_DATA );
    return 0;
  }
  /* Call progress monitor hook if present */
  if( cinfo->progress != NULL ) {
    cinfo->progress->pass_counter = ( long ) cinfo->output_scanline;
    cinfo->progress->pass_limit = ( long ) cinfo->output_height;
    ( *cinfo->progress->progress_monitor )( ( j_common_ptr ) cinfo );
  }
  /* Process some data */
  row_ctr = 0;
  ( *cinfo->main->process_data )( cinfo, scanlines, &row_ctr, max_lines );
  cinfo->output_scanline += row_ctr;
  return row_ctr;
}

JDIMENSION jpeg_read_raw_data( j_decompress_ptr cinfo, JSAMPIMAGE data,
                               JDIMENSION max_lines ) {
  JDIMENSION lines_per_iMCU_row;
  if( cinfo->global_state != DSTATE_RAW_OK )
  { ERREXIT1( cinfo, JERR_BAD_STATE, cinfo->global_state ); }
  if( cinfo->output_scanline >= cinfo->output_height ) {
    WARNMS( cinfo, JWRN_TOO_MUCH_DATA );
    return 0;
  }
  /* Call progress monitor hook if present */
  if( cinfo->progress != NULL ) {
    cinfo->progress->pass_counter = ( long ) cinfo->output_scanline;
    cinfo->progress->pass_limit = ( long ) cinfo->output_height;
    ( *cinfo->progress->progress_monitor )( ( j_common_ptr ) cinfo );
  }
  /* Verify that at least one iMCU row can be returned. */
  lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size;
  if( max_lines < lines_per_iMCU_row )
  { ERREXIT( cinfo, JERR_BUFFER_SIZE ); }
  /* Decompress directly into user's buffer. */
  if( !( *cinfo->coef->decompress_data )( cinfo, data ) )
  { return 0; }			/* suspension forced, can do nothing more */
  /* OK, we processed one iMCU row. */
  cinfo->output_scanline += lines_per_iMCU_row;
  return lines_per_iMCU_row;
}


/* Additional entry points for buffered-image mode. */

#ifdef D_MULTISCAN_FILES_SUPPORTED

wxjpeg_boolean jpeg_start_output( j_decompress_ptr cinfo, int scan_number ) {
  if( cinfo->global_state != DSTATE_BUFIMAGE &&
      cinfo->global_state != DSTATE_PRESCAN )
  { ERREXIT1( cinfo, JERR_BAD_STATE, cinfo->global_state ); }
  /* Limit scan number to valid range */
  if( scan_number <= 0 )
  { scan_number = 1; }
  if( cinfo->inputctl->eoi_reached &&
      scan_number > cinfo->input_scan_number )
  { scan_number = cinfo->input_scan_number; }
  cinfo->output_scan_number = scan_number;
  /* Perform any dummy output passes, and set up for the real pass */
  return output_pass_setup( cinfo );
}

wxjpeg_boolean jpeg_finish_output( j_decompress_ptr cinfo ) {
  if( ( cinfo->global_state == DSTATE_SCANNING ||
        cinfo->global_state == DSTATE_RAW_OK ) && cinfo->buffered_image ) {
    /* Terminate this pass. */
    /* We do not require the whole pass to have been completed. */
    ( *cinfo->master->finish_output_pass )( cinfo );
    cinfo->global_state = DSTATE_BUFPOST;
  } else if( cinfo->global_state != DSTATE_BUFPOST ) {
    /* BUFPOST = repeat call after a suspension, anything else is error */
    ERREXIT1( cinfo, JERR_BAD_STATE, cinfo->global_state );
  }
  /* Read markers looking for SOS or EOI */
  while( cinfo->input_scan_number <= cinfo->output_scan_number &&
         ! cinfo->inputctl->eoi_reached ) {
    if( ( *cinfo->inputctl->consume_input )( cinfo ) == JPEG_SUSPENDED )
    { return FALSE; }		/* Suspend, come back later */
  }
  cinfo->global_state = DSTATE_BUFIMAGE;
  return TRUE;
}

#endif
